package org.qq.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

import java.util.*;

public class BloodRelationConverter {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static class BloodRelation {
        private final Map<String, FieldNode> nodeMap = new HashMap<>();
        private final List<Relation> relations = new ArrayList<>();
        private final Map<String, List<String>> columnSourcesMap = new HashMap<>();
        private int currentIndex = 0;

        public void addRelation(String target, List<String> sources) {
            columnSourcesMap.computeIfAbsent(target, k -> new ArrayList<>()).addAll(sources);
        }

        private FieldNode createSourceFieldNode(String fieldPath) {
            currentIndex++;
            return new FieldNode(fieldPath, true, currentIndex, 1);
        }

        private FieldNode createTargetFieldNode(String fieldPath) {
            return new FieldNode(fieldPath, true, currentIndex, 2);
        }

        public ObjectNode buildResult() {
            // 按照字段名称排序，确保结果一致
            List<Map.Entry<String, List<String>>> sortedEntries = new ArrayList<>(columnSourcesMap.entrySet());
            sortedEntries.sort(Map.Entry.comparingByKey());

            for (Map.Entry<String, List<String>> entry : sortedEntries) {
                String targetField = entry.getKey();
                List<String> sourceFields = entry.getValue();

                FieldNode targetNode = createTargetFieldNode(targetField);
                Relation relation = new Relation(targetNode);

                for (String sourceField : sourceFields) {
                    FieldNode sourceNode = createSourceFieldNode(sourceField);
                    relation.addRefField(sourceNode);
                }

                relations.add(relation);
            }

            ObjectNode result = mapper.createObjectNode();
            result.put("code", 0);

            ObjectNode data = result.putObject("data");

            // withProcessData
            ObjectNode withProcessData = data.putObject("withProcessData");
            withProcessData.put("size", 4); // 固定为4
            withProcessData.put("level", 2); // 固定为2层结构
            withProcessData.set("data", mapper.valueToTree(relations));

            // noProcessData
            ObjectNode noProcessData = data.putObject("noProcessData");
            noProcessData.put("size", 4);
            noProcessData.put("level", 2);
            noProcessData.putArray("data");

            return result;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    static class FieldNode {
        private final String fieldName;
        private final boolean isFinal;
        private final int index;
        private final int level;

        public FieldNode(String fieldName, boolean isFinal, int index, int level) {
            this.fieldName = fieldName;
            this.isFinal = isFinal;
            this.index = index;
            this.level = level;
        }

        // Getters
        public String getFieldName() {
            return fieldName;
        }

        public boolean isFinal() {
            return isFinal;
        }

        public int getIndex() {
            return index;
        }

        public int getLevel() {
            return level;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    static class Relation {
        private final List<FieldNode> refFields = new ArrayList<>();
        private final FieldNode targetField;

        public Relation(FieldNode targetField) {
            this.targetField = targetField;
        }

        public void addRefField(FieldNode field) {
            refFields.add(field);
        }

        // Getters
        public List<FieldNode> getRefFields() {
            return refFields;
        }

        public FieldNode getTargetField() {
            return targetField;
        }
    }

    public static String convert(String inputJson) throws JsonProcessingException {
        JsonNode root = mapper.readTree(inputJson);
        BloodRelation relation = new BloodRelation();

        String schema = root.get("schema").asText();
        String table = root.get("table").asText();

        // 收集所有列的血缘关系
        for (JsonNode col : root.get("columns")) {
            String targetCol = schema + "." + table + "." + col.get("column").asText();
            List<String> sources = new ArrayList<>();

            for (JsonNode source : col.get("sourceColumns")) {
                String tableName = source.get("tableName").asText();
                String columnName = source.get("columnName").asText();
                sources.add(tableName + "." + columnName);
            }

            relation.addRelation(targetCol, sources);
        }

        return mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(relation.buildResult());
    }

    /**
     * 合并两个血缘关系JSON字符串，构建树形结构的血缘关系
     * @param firstJson 第一个血缘关系JSON
     * @param secondJson 第二个血缘关系JSON
     * @return 合并后的树形血缘关系JSON字符串
     * @throws JsonProcessingException 如果解析JSON出错
     */
    public static String mergeAndBuildTree(String firstJson, String secondJson) throws JsonProcessingException {
        // 解析两个JSON
        JsonNode firstRoot = mapper.readTree(firstJson);
        JsonNode secondRoot = mapper.readTree(secondJson);

        // 创建血缘图的节点映射表，键是表名.列名
        Map<String, TreeNode> nodeMap = new HashMap<>();

        // 处理第一个血缘关系
        processBloodRelation(firstRoot, nodeMap, false);

        // 处理第二个血缘关系
        processBloodRelation(secondRoot, nodeMap, true);

        // 构建树形结构
        List<TreeNode> rootNodes = buildTree(nodeMap);

        // 构建返回结果
        ObjectNode result = mapper.createObjectNode();
        result.put("code", 0);

        ObjectNode data = result.putObject("data");

        // 构建withProcessData
        ObjectNode withProcessData = data.putObject("withProcessData");
        withProcessData.put("size", nodeMap.size());

        // 计算树的最大深度
        int maxLevel = calculateMaxLevel(rootNodes);
        withProcessData.put("level", maxLevel);

        // 将树形结构转换为JSON
        withProcessData.set("data", mapper.valueToTree(rootNodes));

        // 构建noProcessData（空数据）
        ObjectNode noProcessData = data.putObject("noProcessData");
        noProcessData.put("size", 0);
        noProcessData.put("level", 0);
        noProcessData.putArray("data");

        return mapper.writerWithDefaultPrettyPrinter()
                .writeValueAsString(result);
    }

    /**
     * 处理单个血缘关系JSON，将其添加到节点映射中
     * @param root JSON根节点
     * @param nodeMap 节点映射表
     * @param isSecond 是否是第二个血缘关系
     */
    private static void processBloodRelation(JsonNode root, Map<String, TreeNode> nodeMap, boolean isSecond) {
        String schema = root.get("schema").asText();
        String table = root.get("table").asText();

        // 处理所有列的血缘关系
        for (JsonNode col : root.get("columns")) {
            String column = col.get("column").asText();
            String fullColumnName = schema + "." + table + "." + column;

            // 获取或创建目标列节点
            TreeNode targetNode = nodeMap.computeIfAbsent(fullColumnName,
                    k -> new TreeNode(column, table, schema));

            // 处理源列
            for (JsonNode source : col.get("sourceColumns")) {
                String sourceTableName = source.get("tableName").asText();
                String sourceColumnName = source.get("columnName").asText();
                String sourceFullName = sourceTableName + "." + sourceColumnName;

                // 解析schema和table
                String[] parts = sourceTableName.split("\\.");
                String sourceSchema = parts.length > 1 ? parts[0] : "";
                String sourceTable = parts.length > 1 ? parts[1] : parts[0];

                // 获取或创建源列节点
                TreeNode sourceNode = nodeMap.computeIfAbsent(sourceFullName,
                        k -> new TreeNode(sourceColumnName, sourceTable, sourceSchema));

                // 建立父子关系
                if (isSecond) {
                    // 如果是第二个血缘关系，源节点是父节点，目标节点是子节点
                    sourceNode.addChild(targetNode);
                } else {
                    // 如果是第一个血缘关系，目标节点是父节点，源节点是子节点
                    targetNode.addChild(sourceNode);
                }
            }
        }
    }

    /**
     * 构建树形结构，找出所有根节点（没有父节点的节点）
     * @param nodeMap 节点映射表
     * @return 根节点列表
     */
    private static List<TreeNode> buildTree(Map<String, TreeNode> nodeMap) {
        // 标记所有有父节点的节点
        Set<TreeNode> hasParent = new HashSet<>();

        for (TreeNode node : nodeMap.values()) {
            hasParent.addAll(node.getChildren());
        }

        // 找出所有没有父节点的节点作为根节点
        List<TreeNode> rootNodes = new ArrayList<>();
        for (TreeNode node : nodeMap.values()) {
            if (!hasParent.contains(node)) {
                rootNodes.add(node);
            }
        }

        return rootNodes;
    }

    /**
     * 计算树的最大深度
     * @param nodes 节点列表
     * @return 最大深度
     */
    private static int calculateMaxLevel(List<TreeNode> nodes) {
        int maxLevel = 0;
        for (TreeNode node : nodes) {
            maxLevel = Math.max(maxLevel, calculateNodeLevel(node, 1));
        }
        return maxLevel;
    }

    /**
     * 递归计算节点的深度
     * @param node 当前节点
     * @param currentLevel 当前深度
     * @return 最大深度
     */
    private static int calculateNodeLevel(TreeNode node, int currentLevel) {
        if (node.getChildren().isEmpty()) {
            return currentLevel;
        }

        int maxChildLevel = currentLevel;
        for (TreeNode child : node.getChildren()) {
            maxChildLevel = Math.max(maxChildLevel, calculateNodeLevel(child, currentLevel + 1));
        }
        return maxChildLevel;
    }

    /**
     * 表示血缘树中的一个节点
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    static class TreeNode {
        private String name;
        private String tableName;
        private String schemaName;
        private List<TreeNode> children = new ArrayList<>();

        public TreeNode(String name, String tableName, String schemaName) {
            this.name = name;
            this.tableName = tableName;
            this.schemaName = schemaName;
        }

        public void addChild(TreeNode child) {
            if (!children.contains(child)) {
                children.add(child);
            }
        }

        // Getters
        public String getName() {
            return name;
        }

        public String getTableName() {
            return tableName;
        }

        public String getSchemaName() {
            return schemaName;
        }

        public List<TreeNode> getChildren() {
            return children;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            TreeNode treeNode = (TreeNode) o;
            return Objects.equals(name, treeNode.name) &&
                   Objects.equals(tableName, treeNode.tableName) &&
                   Objects.equals(schemaName, treeNode.schemaName);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, tableName, schemaName);
        }
    }

    public static void main(String[] args) throws Exception {
        String input = ""; // 替换为实际JSON输入
        System.out.println(convert(input));
    }
}